﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Elderos.Ontology;
using Elderos.Utils;

namespace Elderos.Highlight.Search
{
    public class CompactSearcher : TextSearcherBase
    {
        private SortedSet<int> _lengths = new SortedSet<int>();
        private IDictionary<ulong, List<int>> _synonyms;

        public CompactSearcher(ISynonymSource synonymSource, int synonymEntityCount) : base(synonymSource)
        {
            _synonyms = new Dictionary<ulong, List<int>>(synonymEntityCount);
        }

        public static UInt64 CalculateHash(string str)
        {
            UInt64 hash = 3074457345618258791ul;
            for (int i = 0; i < str.Length; i++)
            {
                hash += char.ToLowerInvariant(str[i]);
                hash *= 3074457345618258799ul;
            }
            return hash;
        }

        protected override void ProcessSynonym(Synonym synonym)
        {
            _lengths.Add(synonym.Syno.Length);
            string syno = synonym.Syno;
            var hash = CalculateHash(syno);

            if (_synonyms.ContainsKey(hash))
            {
                var firstSyno = _synonyms[hash];
                firstSyno.AddRange(synonym.EntityIDs.Where(x => !firstSyno.Contains(x)));
                firstSyno.TrimExcess();
                return;
            }

            _synonyms.Add(hash, synonym.EntityIDs);
        }

        protected override List<Position> InnerSearch(PreparedText preparedText)
        {
            var result = new List<Position>();

            string text = preparedText.Text;
            for (int start = 0; start < text.Length; start++)
            {
                if (!text.IsCorrectLeftPosition(start)) continue;



                UInt64 hash = 3074457345618258791ul;
                int maxLength = _lengths.Last();

                for (int offset = 0; offset <= maxLength && start + offset < text.Length; offset++)
                {
                    hash += char.ToLowerInvariant(text[start + offset]);
                    hash *= 3074457345618258799ul;
                    if (_lengths.Contains(offset))
                    {
                        int length = offset + 1;
                        if (!text.IsCorrectRightPosition(start + length)) continue;
                        List<int> entityIDs;
                        if (_synonyms.TryGetValue(hash, out entityIDs))
                        {
                            result.Add(new Position(start, length, entityIDs, text.Substring(start, length)));
                        }
                    }
                }
            }

            return result;
        }
    }
}
